package com.eliza.v.http.base

import com.eliza.v.http.VertxTools
import io.vertx.core.AbstractVerticle
import io.vertx.core.Future
import io.vertx.core.Promise
import io.vertx.core.Vertx
import io.vertx.core.http.HttpMethod
import io.vertx.core.json.JsonObject
import io.vertx.ext.web.Router
import io.vertx.ext.web.RoutingContext


/*-*- coding:utf-8 -*-
 * @Author  : debi
 * @Time    : 2/2/22
 * @Software: IntelliJ IDEA
 */
class HttpProcess : AbstractVerticle() {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            VertxTools.runVertical(HttpProcess::class.java)
        }
    }


    override fun start(startPromise: Promise<Void>?) {
        super.start(startPromise)
//        writeNoBlock()
//        sendFuture()  //err
//        block() //err
//        path()
//        capturePath()//err
        httpRoute()
    }

    private fun writeNoBlock() {
        val router = Router.router(vertx)
        val route = router.route("/writeNoBlock")
        /**
         * 上面的示例route1中写入响应，
         * 然后 5 秒后route2写入响应，
         * 然后 5 秒后route3写入响应并结束响应
         * 必须没有任何线程阻塞
         * */
        route.handler { ctx: RoutingContext ->
            val response = ctx.response()

            // 开启分块响应，因为我们将在执行其他处理器时添加数据
            response.isChunked = true
            response.write("route1\n")

            // Call the next matching route after a 5 second delay
            ctx.vertx().setTimer(500) { ctx.next() }
        }
        route.handler { ctx: RoutingContext ->
            val response = ctx.response()
            response.write("route2\n")

            ctx.vertx().setTimer(500) { tid: Long? -> ctx.next() }
        }
        route.handler { ctx: RoutingContext ->
            ctx.response().run {
                write("route3")
                ctx.end()
            }
        }

        VertxTools.result(vertx, this, "writeNoBlock", router, 8080)

    }

    private fun sendFuture() {
/*

    处理程序非常强大，因为它们允许您构建非常复杂的应用程序。对于简单的响应，
    例如，直接从 vert.x API 返回异步响应，路由器包含一个处理程序的快捷方式，以确保
            响应以 JSON 格式返回。
            如果处理处理程序发生错误，则返回正确的错误。
            如果序列化对 JSON 的响应出错，则返回正确的错误。
*/
        val router = Router.router(vertx)



        router.get("/SendFuture1")
            .respond { ctx -> Future.succeededFuture(JsonObject().put("hello", "SendFuture1")) }

        router.route("/SendFuture2")
            .respond { ctx -> Future.succeededFuture(JsonObject().put("hello", "vtSendFuture2")) }

        /*提供的函数调用write或，您也可以将其用于非 JSON 响应end*/
        router.route("/SendFuture3")
            .respond { ctx -> ctx.response().putHeader("Content-Type", "text/plain").end("vtSendFuture3") }

        router["SendFuture4"] // in this case, the handler ensures that the connection is ended
            .respond { ctx ->
                ctx.response().setChunked(true).write("Write some vtSendFuture4 ...")
            }


        VertxTools.result(vertx, this, "sendFuture", router, 8080)


    }

    /**
     * 阻塞
     */
    private fun block() {
        /*
        您无法在普通处理程序中执行此操作，因此我们提供了在路由上设置阻塞处理程序的能力。
          阻塞处理程序看起来就像一个普通的处理程序，
          但它是由 Vert.x 使用来自工作池的线程调用的，而不是使用事件循环*/

        /*默认情况下，在相同上下文（例如相同的verticle实例）上执行的任何阻塞处理程序都是有序的——
        这意味着下一个在前一个完成之前不会执行*/
        val router = Router.router(vertx)

/*        router.route().blockingHandler { ctx ->

            // Do something that might take some time synchronously
            // Now call the next handler
            ctx.next()
        }*/

        /*
        * 如果您不关心排序并且不介意您的阻塞处理程序并行执行，
        * 您可以ordered使用 将阻塞处理程序指定为 false
    如果您需要处理来自阻塞处理程序的多部分表单数据，
        * 则必须首先使用非阻塞处理程序才能调用setExpectMultipart(true).*/
        router.post("/block").handler { ctx ->
            ctx.request().isExpectMultipart = true
            ctx.next()
        }.blockingHandler { ctx ->
            ctx.response().write("blockingHandler")
        }


        VertxTools.result(vertx, this, "block", router, 8080)


    }

    /**
     * /some/path/      path/，path//
     * /some/path       path，path/，path//
     *  /some/path / *  以开头
     */
    private fun path() {

        val router = Router.router(vertx)

        /*
        可以设置路由以匹配来自请求 URI 的路径。在这种情况下，它将匹配具有与指定路径相同的路径的任何请求。
在下面的示例中，将为请求调用处理程序*/
        router.route().path("/path/").handler { ctx: RoutingContext ->
            println("path(\"/path/\")")
            //  以/some/path/
            // `/some/path/`
            // `/some/path//`
            //
            // but not:
            // `/some/path` the end slash in the path makes it strict
            // `/some/path/subdir`
            println("/path/ :${ctx.request().body().toString()}")

            ctx.response().setChunked(true).write("/path/")
            ctx.end()

        }


/*不以斜杠结尾的路径并不严格，这意味着尾部斜杠是可选的，并且无论如何它们都匹配*/
        router.route().path("/path").handler { ctx: RoutingContext ->
            // This handler will be called for the following request paths:
            //  以/some/path
            // `/some/path`
            // `/some/path/`
            // `/some/path//`
            //
            // but not:
            // `/some/path/subdir`
            println("path(\"/path\")")
            println("/path :${ctx.request().body().toString()}")
            ctx.response().setChunked(true).write("/path")
            ctx.end()

        }

        VertxTools.result(vertx, this, "path", router, 8080)

    }

    private fun capturePath() {

        /* 占位符由 : 后跟参数名称组成
        参数名称由任何字母字符、数字字符或下划线组成
        受限：可以切换到扩展名称规则，其中包括 2 个额外字符-和$. 扩展参数规则作为系统属性启用
            -Dio.vertx.web.route.param.extended-pattern=true
         */

        val router = Router.router(vertx)
        router.route(HttpMethod.GET, "/capturePath/:from-:to")
            .handler { ctx ->
                // when handling requests to /capturePath/AMS-SFO
                // will set:
                var from = ctx.pathParam("from"); // AMS
                var to = ctx.pathParam("to"); // SFO
                /*请记住，当使用的参数命名模式不是“扩展”模式时，这将无法按预期工作。
                    这是因为在这种情况下，“-”被认为是变量名的一部分，而不是分隔符*/
                ctx.response().isChunked = true
                println("$from : $to")
                ctx.response().write("$from : $to")
                ctx.end()
            }
        router.route(
            HttpMethod.POST,
            "/capturePath/:productType/:productID/"
        ).handler { ctx ->
            /*如果向 path: 发出 POST 请求，
            /capturePath/tools/drill123/
            接收 路径里的参数
            则路由将匹配并productType 接收 valuetools
            并将productID接收 value drill123。*/
            ctx.response().isChunked = true

            var productType = ctx.pathParam("productType");
            var productID = ctx.pathParam("productID")
            println("$productType :$productID")
            println(Thread.currentThread())
            ctx.response().write("capturePath :$productType :$productID")
            ctx.end()

        }

/*
        //参数不需要是路径段。例如，像下面这样的路径参数也是有效的
        router(vertx).route(HttpMethod.GET, "/flights/:from-:to")
            .handler { ctx ->
                var from = ctx.pathParam("from"); // AMS
                var to = ctx.pathParam("to"); // SFO

                ctx.end("$from:$to")
            }
*/
        /**
         * 正则获取路径参数
         */
        router.routeWithRegex(".*foo").pathRegex("\\/([^\\/]+)\\/([^\\/]+)").handler { ctx: RoutingContext ->
            val productType = ctx.pathParam("param0")
            val productID = ctx.pathParam("param1")
            ctx.response().write("capturePath :$productType :$productID")
            ctx.end()

        }


        VertxTools.result(vertx, this, "capturePath", router, 8080)

    }

    private fun httpRoute() {
        val router = Router.router(vertx)
        router.route().method(HttpMethod.POST).method(HttpMethod.GET).path("/httpRoute1")
            .handler { rc: RoutingContext ->
                println("httpRoute1: " + rc.request().getParam("name"))
                rc.response().end("httpRoute1")
            }

        router.route(HttpMethod.POST, "/httpRoute2").handler { rc ->
            println("httpRoute:--:" + rc.request().getParam("name"))
            rc.response().end("httpRoute2")
        }
        router.post("/httpRoute3").handler { rc ->
            println("httpRoute:--:" + rc.request().getParam("name"))
            rc.response().end("httpRoute2")

        }

        VertxTools.result(vertx, this, "httpRoute", router, 8080)

    }


}